{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 符号布尔型和模糊布尔型\n",
    "\n",
    "\n",
    "本页描述了 SymPy 中的符号布尔值是什么，以及它与 SymPy 的许多部分中使用的三值 fuzzy-bools 的关系。本文还讨论了在编写使用三值逻辑的代码时出现的一些常见问题，以及如何正确处理这些问题。\n",
    "\n",
    "## 符号布尔与三值布尔\n",
    "\n",
    "像 `x.ispositive` 这样的假设查询会给出 `fuzzy-bool` `True`、 `False` 或 `None` 结果。这些是底层的 Python 对象，而不是 SymPy 的符号布尔表达式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "from sympy import Symbol, symbols\n",
    "xpos = Symbol('xpos', positive=True)\n",
    "xneg = Symbol('xneg', negative=True)\n",
    "x = Symbol('x')\n",
    "print(xpos.is_positive)\n",
    "print(xneg.is_positive)\n",
    "print(x.is_positive)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A 无结果作为一个模糊布尔应该解释为意味着“可能”或“未知”。\n",
    "\n",
    "使用不等式时，可以找到 SymPy 中符号布尔类的一个示例。当一个不等式不知道是否为真时，一个布尔值可以象征性地表示不确定的结果:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "x > 0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "sympy.core.relational.StrictGreaterThan"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(xpos > 0)\n",
    "print(xneg > 0)\n",
    "print(x > 0)\n",
    "type(x > 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后一个例子展示了当一个不等式是不确定的时候会发生什么: 我们得到了一个 `StrictGreaterThan` 的例子，它将不等式表示为一个符号表达式。在内部，当试图计算像 `a > b` SymPy 这样的不等式时，将计算`(a-b).is_extended_positive`。如果结果是 `True` 或 `False`，那么 SymPy 的符号。 `True` 或者 `False` 将被返回。如果结果是 `None`，那么返回一个未计算的 `StrictGreaterThan`，如上面的 `x > 0`所示。\n",
    "\n",
    "像 `xpos > 0`这样的查询返回的是 `S.True` 而不是 `True`，这并不明显，因为两个对象的显示方式是相同的，但是我们可以使用 Python is 操作符检查这一点:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "from sympy import S\n",
    "print(xpos.is_positive is True)\n",
    "print(xpos.is_positive is S.true)\n",
    "print((xpos > 0) is True)\n",
    "print((xpos > 0) is S.true)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 SymPy 中没有一般意义上的 `None` 的象征类比。在低级别假设查询提供 `None` 的情况下，符号查询将导致未计算的符号布尔值(例如，`x > 0`)。我们可以使用符号布尔值作为符号表达式的一部分，比如分段函数`Piecewise`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle \\begin{cases} 1 & \\text{for}\\: x > 0 \\\\2 & \\text{otherwise} \\end{cases}$"
      ],
      "text/plain": [
       "Piecewise((1, x > 0), (2, True))"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sympy import Piecewise\n",
    "p = Piecewise((1, x > 0), (2, True))\n",
    "p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle 1$"
      ],
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.subs(x, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里 `p` 表示一个等于 `1` 的表达式，如果 `x > 0`，或者等于`2`。未求值的布尔不等式 `x > 0`表示以符号形式确定表达式值的条件。当我们用一个值代替 `x` 时，这个不等式就会解析为 `s` 真，然后 `Piecewise` 求值为`1`或`2`。\n",
    "\n",
    "当使用 fuzzy-bool 而不是符号布尔值时，也不会出现同样的情况:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "\nSecond argument must be a Boolean, not `NoneType`",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-efc1636600cf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mp2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPiecewise\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_positive\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/functions/elementary/piecewise.py\u001b[0m in \u001b[0;36m__new__\u001b[0;34m(cls, *args, **options)\u001b[0m\n\u001b[1;32m    125\u001b[0m         \u001b[0;32mfor\u001b[0m \u001b[0mec\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    126\u001b[0m             \u001b[0;31m# ec could be a ExprCondPair or a tuple\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 127\u001b[0;31m             \u001b[0mpair\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mExprCondPair\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'args'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mec\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    128\u001b[0m             \u001b[0mcond\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpair\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcond\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    129\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mcond\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mfalse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/functions/elementary/piecewise.py\u001b[0m in \u001b[0;36m__new__\u001b[0;34m(cls, expr, cond)\u001b[0m\n\u001b[1;32m     28\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     29\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcond\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mBoolean\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 30\u001b[0;31m             raise TypeError(filldedent('''\n\u001b[0m\u001b[1;32m     31\u001b[0m                 \u001b[0mSecond\u001b[0m \u001b[0margument\u001b[0m \u001b[0mmust\u001b[0m \u001b[0mbe\u001b[0m \u001b[0ma\u001b[0m \u001b[0mBoolean\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     32\u001b[0m                 not `%s`''' % func_name(cond)))\n",
      "\u001b[0;31mTypeError\u001b[0m: \nSecond argument must be a Boolean, not `NoneType`"
     ]
    }
   ],
   "source": [
    "p2 = Piecewise((1, x.is_positive), (2, True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Piecewise`不能使用 `None` 作为条件，因为与不等式 `x > 0`不同，它没有给出任何信息。有了不等式，将来一旦知道 `x` 的值，就可以决定条件是否为 `True` 或 `False`。不能以这种方式使用 `None` 值，因此它被拒绝。\n",
    "\n",
    "> 注意: 我们可以在`Piecewise`中使用 `True`，因为 `True` 符号等同于 `s.True`。`None` 等同于只是又给出 `None`，这不是一个有效的象征性对象。\n",
    "\n",
    "SymPy 中还有许多其他符号布尔类型。模糊布尔和符号布尔之间的区别同样适用于所有其他 SymPy 布尔类型。为了给出一个不同的例子， `Contains` 表示一个对象包含在一个集合中的语句:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "Contains(y, Reals)\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "from sympy import Reals, Contains\n",
    "x = Symbol('x', real=True)\n",
    "y = Symbol('y')\n",
    "print(Contains(x, Reals))\n",
    "print(Contains(y, Reals))\n",
    "print(Contains(y, Reals).subs(y, 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对应于 `Contains` 的 Python 运算符在。 `In` 的一个奇怪之处是它只能计算 bool (True 或 False) ，因此如果结果不确定，则会引发异常:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "did not evaluate to a bool: (-oo < y) & (y < oo)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-16-99eb6b1186fe>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mI\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mReals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mReals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mReals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/sets/sets.py\u001b[0m in \u001b[0;36m__contains__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m    690\u001b[0m             \u001b[0;31m# x in y must evaluate to T or F; to entertain a None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    691\u001b[0m             \u001b[0;31m# result with Set use y.contains(x)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 692\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'did not evaluate to a bool: %r'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    693\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    694\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: did not evaluate to a bool: (-oo < y) & (y < oo)"
     ]
    }
   ],
   "source": [
    "from sympy import I\n",
    "print(2 in Reals)\n",
    "print(I in Reals)\n",
    "print(x in Reals)\n",
    "print(y in Reals)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以通过使用 `Contains(x，Reals)`或 `Reals.Contains(x)`而不是使用 `x in Reals` 来避免异常。\n",
    "\n",
    "## 三值逻辑与模糊布尔\n",
    "\n",
    "无论我们使用模糊布尔 `fuzzy-bool` 还是符号布尔 `symbolic Boolean`，我们总是需要意识到查询可能是不确定的。但是在这两种情况下，如何编写处理这个问题的代码是不同的。我们先来看看 `fuzzy-bool`。考虑以下功能:\n",
    "\n",
    "`both_positive` 函数应该告诉我们 `a` 和 `b` 是否都是正。然而， 如果两个各种的任意一个 `is_positive` 给出 `None` 那么 `both_positive` 查询都将失败:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "def both_positive(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    if a.is_positive and b.is_positive:\n",
    "        return True\n",
    "    else:\n",
    "        return False\n",
    "\n",
    "print(both_positive(S(1), S(1)))\n",
    "print(both_positive(S(1), S(-1)))\n",
    "print(both_positive(S(-1), S(-1)))\n",
    "x = Symbol('x') # may or may not be positive\n",
    "print(both_positive(S(1), x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 注意: 我们需要使用 `s` 对这个函数的参数进行符号化，因为这些假设只定义在 SymPy 对象上，而不是常规的 Python `int` 对象上。\n",
    "\n",
    "这里 `False` 是不正确的，因为 `x` 可能是正的，这样两个参数都是正的。我们在这里得到 `False` 是因为 `x.is_positive` 给出了 `None` 并且 Python 将 `None` 视为 `falsey`。\n",
    "\n",
    "为了正确处理所有可能的情况，我们需要区分用于识别真假情况的逻辑。一个改进的功能可能是下面的函数定义。\n",
    "\n",
    "这个函数现在可以处理 `a` 和 `b` 的所有 `True`、 `False` 或 `None` 情况，并且总是返回一个模糊 `bool`，表示“ a 和 b 都是肯定的”语句是真的、假的还是未知的:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "None\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "def both_positive_better(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    if a.is_positive is False or b.is_positive is False:\n",
    "        return False\n",
    "    elif a.is_positive is True and b.is_positive is True:\n",
    "        return True\n",
    "    else:\n",
    "        return None\n",
    "\n",
    "print(both_positive_better(S(1), S(1)))\n",
    "print(both_positive_better(S(1), S(-1)))\n",
    "x = Symbol('x')\n",
    "y = Symbol('y', positive=True)\n",
    "print(both_positive_better(S(1), x))\n",
    "print(both_positive_better(S(-1), x))\n",
    "print(both_positive_better(S(1), y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 `fuzzy-bools` 时需要注意的另一种情况是 Python 的 `not` 操作符的否定，例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "x = Symbol('x')\n",
    "print(x.is_positive)\n",
    "print(not x.is_positive)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "正确否定一个模糊布尔 `None` 仍然是 `None`。如果我们不知道“ x is positive”是 `True` 还是 `False` ，那么我们也不知道它的否定“ x is not positive”是 `True` 还是 `False` 。我们得到 `True` 的原因还是因为 `None` 被认为是 `falsey` 。当 `None` 与 `not` 等逻辑运算符一起使用时，它将首先转换为 `bool`，然后进行否定: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(bool(None))\n",
    "print(not bool(None))\n",
    "print(not None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果使用正确，`None` 被视为 `falsey` 是有用的。例如，我们可能想做的事情，只有当 `x` 已知为正时，在这种情况下，我们可以做"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x is definitely positive\n"
     ]
    }
   ],
   "source": [
    "x = Symbol('x', positive=True)\n",
    "if x.is_positive:\n",
    "    print(\"x is definitely positive\")\n",
    "else:\n",
    "    print(\"x may or may not be positive\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们理解替代条件分支指的是两个情况(`False` 和 `None`) ，那么这可能是编写条件句的有用方法。当我们真的需要区分所有的情况时，我们需要使用像 x.is _ positive is False 这样的东西。但是我们需要注意的是，使用 Python 的二进制逻辑运算符，如 not 或和 fuzzy bools，因为它们不能正确处理不确定的情况。\n",
    "\n",
    "事实上 SymPy 具有内部功能，可以正确处理 fuzzy-bools:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n",
      "None\n",
      "True\n",
      "None\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "from sympy.core.logic import fuzzy_not, fuzzy_and\n",
    "print(fuzzy_not(True))\n",
    "print(fuzzy_not(False))\n",
    "print(fuzzy_not(None))\n",
    "print(fuzzy_and([True, True]))\n",
    "print(fuzzy_and([True, None]))\n",
    "print(fuzzy_and([False, None]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 fuzzy 和函数，我们可以更简单地写出这两个正函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def both_positive_best(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    return fuzzy_and([a.is_positive, b.is_positive])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 fuzzy 和，fuzzy 和 fuzzy 不会导致更简单的代码，也可以减少引入逻辑错误的机会，因为代码看起来更像普通的二进制逻辑。\n",
    "\n",
    "## 带有象征性布尔值的三值逻辑\n",
    "\n",
    "当使用符号布尔值而不是模糊布尔值的时候，没有默默地被当作虚假值处理的问题不会出现，所以它更容易不以逻辑错误结束。然而，如果处理不当，不确定的情况通常会导致引发异常。\n",
    "\n",
    "这次我们将尝试使用符号布尔来实现这个 `both_positive`:\n",
    "\n",
    "第一个区别是，我们返回符号布尔对象 `S.True` 和 `S.False`，而不返回 `True` 和 `False`。第二个区别是，我们测试 `a > 0`而不是 `a.is_positive`。我们试试这个"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "cannot determine truth value of Relational",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-25-975886dd696e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mboth_positive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mSymbol\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'x'\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# may or may not be positive\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mboth_positive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-25-975886dd696e>\u001b[0m in \u001b[0;36mboth_positive\u001b[0;34m(a, b)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mboth_positive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m     \u001b[0;34m\"\"\"ask whether a and b are both positive\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;32mif\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mS\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/core/relational.py\u001b[0m in \u001b[0;36m__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    397\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__bool__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot determine truth value of Relational\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    400\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_eval_as_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot determine truth value of Relational"
     ]
    }
   ],
   "source": [
    "def both_positive(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    if a > 0 and b > 0:\n",
    "        return S.true\n",
    "    else:\n",
    "        return S.false\n",
    "\n",
    "print(both_positive(1, 2))\n",
    "print(both_positive(-1, 1))\n",
    "x = Symbol('x')  # may or may not be positive\n",
    "both_positive(x, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在的情况是，当 `x` 不是正数或者不是正数时，测试 `x > 0`给出了一个例外。更准确地说，`x > 0`不会给出异常，但是如果 `x > 0`会给出异常，这是因为 `if` 语句隐式调用 `bool (x > 0)` ，而 bool 会引发。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "cannot determine truth value of Relational",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-26-938438b0664f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mbool\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/core/relational.py\u001b[0m in \u001b[0;36m__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    397\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__bool__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot determine truth value of Relational\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    400\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_eval_as_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot determine truth value of Relational"
     ]
    }
   ],
   "source": [
    "x > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "cannot determine truth value of Relational",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-27-7503ff952c02>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbool\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/core/relational.py\u001b[0m in \u001b[0;36m__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    397\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__bool__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot determine truth value of Relational\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    400\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_eval_as_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot determine truth value of Relational"
     ]
    }
   ],
   "source": [
    "bool(x > 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "cannot determine truth value of Relational",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-28-ce47914d7577>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"x is positive\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/core/relational.py\u001b[0m in \u001b[0;36m__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    397\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__bool__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot determine truth value of Relational\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    400\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_eval_as_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot determine truth value of Relational"
     ]
    }
   ],
   "source": [
    "if x > 0:\n",
    "    print(\"x is positive\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python 表达式 `x > 0`创建一个 SymPy `Boolean`。因为在这种情况下，布尔值不能求值为 `True` 或 `False`，所以我们得到一个未求值的 `StritGreaterThan`。试图将其强制到 `bool (x > 0)`会产生一个异常。这是因为一个普通的 Python `bool` 必须是 `True` 或 `False`，在这种情况下，这两者都是不正确的。\n",
    "\n",
    "同样的问题出现在使用和或不使用符号布尔值时。解决方案是使用 SymPy 的符号 `And`、 `Or` 和 `Not` 或相当于 Python 的按位逻辑运算符 `&` 、 `|` 和 `~` :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x > 0$"
      ],
      "text/plain": [
       "x > 0"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sympy import And, Or, Not\n",
    "x > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "cannot determine truth value of Relational",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-30-94df1394afd8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/opt/anaconda3/lib/python3.8/site-packages/sympy/core/relational.py\u001b[0m in \u001b[0;36m__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    397\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__bool__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 398\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot determine truth value of Relational\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    400\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_eval_as_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot determine truth value of Relational"
     ]
    }
   ],
   "source": [
    "x > 0 and x < 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x > 0 \\wedge x < 1$"
      ],
      "text/plain": [
       "(x > 0) & (x < 1)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "And(x > 0, x < 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x > 0 \\wedge x < 1$"
      ],
      "text/plain": [
       "(x > 0) & (x < 1)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(x > 0) & (x < 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x > 1 \\vee x < 0$"
      ],
      "text/plain": [
       "(x > 1) | (x < 0)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Or(x < 0, x > 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x \\geq 0$"
      ],
      "text/plain": [
       "x >= 0"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Not(x < 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\displaystyle x \\geq 0$"
      ],
      "text/plain": [
       "x >= 0"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "~(x < 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如前所述，如果我们避免在 `if`、 `and`、 `or` 或 `not` 中直接使用 SymPy 布尔值，我们可以创建一个更好的 `both_positive` 的版本。相反，我们可以测试布尔值是否计算为 `S.true` 或 `S.false`:\n",
    "\n",
    "现在在这个版本中我们没有任何例外，如果结果是不确定的，我们将得到一个符号布尔值，表示语句“ `a` 和 `b` 都是正数”为真的条件:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def both_positive_better(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    if (a > 0) is S.false or (b > 0) is S.false:\n",
    "        return S.false\n",
    "    elif (a > 0) is S.true and (b > 0) is S.true:\n",
    "        return S.true\n",
    "    else:\n",
    "        return And(a > 0, b > 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后一种情况表明，实际使用 And 的条件被认为是真实的，从而简化了 And。事实上，我们有"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x > 0\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "print(And(x > 0, 3 > 0))\n",
    "print(And(4 > 0, 3 > 0))\n",
    "print(And(-1 > 0, 3 > 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这意味着我们可以更好地改善 `both_positive_better`。不同的情况根本不需要。相反，我们可以简单地返回 `And`，如果可能的话，让它简化:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "def both_positive_best(a, b):\n",
    "    \"\"\"ask whether a and b are both positive\"\"\"\n",
    "    return And(a > 0, b > 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，这将与任何符号真实的对象，并产生一个符号结果。我们也可以用结果代替，看看它对特定的值是如何起作用的:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "x > 0\n",
      "(x + y > 0) & (x/y > 0)\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(both_positive_best(2, 1))\n",
    "print(both_positive_best(-1, 2))\n",
    "print(both_positive_best(x, 3))\n",
    "condition = both_positive_best(x/y, x + y)\n",
    "print(condition)\n",
    "print(condition.subs(x, 1))\n",
    "print(condition.subs(x, 1).subs(y, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用符号布尔对象时，尽可能避免使用 `if/else` 和其他逻辑运算符(如 `and` 等)来分支它们。不要把计算一个条件当作一个变量来传递。像 `And`、 `Or` 和 `Not` 这样的基本符号运算可以为您解决逻辑问题。\n",
    "\n",
    "## 脚注\n",
    "\n",
    "请注意，SymPy 中所指的 `fuzzy bool` 实际上是关于使用三值逻辑的。在正常情况下, `fuzzy logic` 指的是一个系统，其逻辑值在0和1之间是连续的，这与三值逻辑不同。"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
  },
  "kernelspec": {
   "display_name": "Python 3.9.5 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
